package rm.metrology.shared;

import java.io.Serializable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import com.googlecode.objectify.annotation.Unindexed;

public class MeasurementEntity implements Serializable {

	
	private static final long serialVersionUID = 1L;

	@Unindexed 
	private Long fCreatedAt = System.currentTimeMillis();
	
	@Unindexed
	@NotNull(message="[Staff] is REQUIRED")
	private String fStaff;
	
	@Unindexed
	@NotNull(message="[Expected Value] is REQUIRED")
	@Size(min=0, max=10000, message="[Expected Value] between 0 and 10000")
	private Float fExpValue;
	
	@Unindexed
	@Size(min=1, max=10, message="[Actual Values] between 1 and 10")
	private List<Float> fValues = new ArrayList<Float>();
		
	@Unindexed
	@NotNull(message="[Uncertainty] is REQUIRED")
	@Size(min=0, max=100, message="[Uncertainty] between 0 and 100")
	private Float fUncertainty;
	
	@Unindexed
	private Integer fInaccuracies = 0;
	
	
	protected MeasurementEntity() {
	}
	
	public MeasurementEntity(String staff, Float expValue, Float uncertainty) {
		fStaff = staff;
		fExpValue = expValue;
		fUncertainty = uncertainty;
	}
	
	public final Long getCreatedTime() {
		return fCreatedAt;
	}
	
	public final String getStaff() {
		return fStaff;
	}
	
	public final Float getExpValue() {
		return fExpValue;
	}

	public final Float getUncertainty() {
		return fUncertainty;
	}

	public final List<Float> getActValues() {
		return Collections.unmodifiableList(fValues);
	}

	public final void addActValue(Float actValue1) {
		fValues.add(actValue1);
		evaluate();
	}
	
	public final void clearActValues() {
		fValues.clear();
		evaluate();
	}

	// if -1 then no actual values have been input
	public final Integer getInaccuracyCount() {
		return fInaccuracies;
	}
	
	private void evaluate() {
		fInaccuracies = (fValues.size() == 0) ? -1 : 0;
		if (fInaccuracies < 0) return; //
		for (Float value : fValues) {
			fInaccuracies += (Math.abs(fExpValue - value) > fUncertainty) ? 1 : 0;
		}
	}

	@Override
	public boolean equals(Object obj) {
		Long other;
		if (obj instanceof MeasurementEntity) {
			other = ((MeasurementEntity) obj).getCreatedTime();
		} else if (obj instanceof Long) {
			other = (Long) obj;
		} else {
			return false;
		} 
		return fCreatedAt.equals(other);
	}
	
}
